package com.dongdongshop.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.dongdongshop.dao.CartDaoRepository;
import com.dongdongshop.data.DataResult;
import com.dongdongshop.feignservice.ItemFeignService;
import com.dongdongshop.pojo.cart.Cart;
import com.dongdongshop.pojo.item.TbItem;
import com.dongdongshop.pojo.order.TbOrderItem;
import com.dongdongshop.service.cart.CartService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

/**
 * @Author Eayon
 * @Date 2020/4/4 10:12
 */
@Service
public class CartServiceImpl implements CartService {
    private static final Logger log = LoggerFactory.getLogger(CartServiceImpl.class);

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private CartDaoRepository cartDaoRepository;

    @Autowired
    private ItemFeignService itemFeignService;

    /**
     * 根据用户名，从缓存中获取该用户购物车
     * @param username
     * @return
     */
    @Override
    public List<Cart> findCarttsByUsernameForCache(String username) {
        List<Cart> cartList = (List<Cart>)redisTemplate.boundHashOps("cartList").get(username);
        //如果redis中没有就返回空集合
        if(cartList == null || cartList.size() <= 0){
            log.info("用户：{}  的缓存购物车为空，即将返回空集合",username);
            cartList = new ArrayList<>();
        }
        log.info("用户：{}  的缓存购物车查询完毕，即将返回购物车数据：{}",username, JSONObject.toJSONString(cartList));
        return cartList;
    }


    /**
     * 合并缓存和cookie购物车
     * @param carsByCache
     * @param carsByCookie
     * @return
     */
    @Override
    public List<Cart> mergeCartList(List<Cart> carsByCache, List<Cart> carsByCookie) {
        //遍历cookie中的大购物车
        for (Cart cart : carsByCookie) {
            //遍历商家购物车中的商品明细
            for (TbOrderItem orderItem : cart.getOrderItemList()) {
                //调用方法重新组装redis购物车数据
                //也就是判断cookie购物车中的每一个商品明细。通过调用这个方法去判断，在redis中是否存在
                //不存在就加入到reids的购物车集合然后返回，存在就把这个商品明细价钱和数量进行增加并返回
                carsByCache = addGoodsToCartList(carsByCache, orderItem.getItemId(), orderItem.getNum());
                //那么现在得到的这个cartListRedis就是合并后的购物车集合了。
            }
        }
        log.info("购物车合并完成：{}",JSONObject.toJSONString(carsByCache));
        return carsByCache;
    }

    /**
     * 添加商品到购物车集合并重新组装 然后返回购物车集合
     * @param cartList
     * @param itemId
     * @param num
     * @return
     */
    @Override
    public List<Cart> addGoodsToCartList(List<Cart> cartList, Long itemId, Integer num) {
        //使用Feign调用item服务，根据itemId查询sku信息
        DataResult<TbItem> dataResult = itemFeignService.findItemById(itemId);
        TbItem item = dataResult.getData();
        //如果该用户传递的id查询不到该商品sku信息，那就抛异常给调用我们的mall_web服务的方法
        if(item==null){
            throw new RuntimeException("传递的itemId查询不到该商品sku信息");
        }
        //sku商品有个status字段，1=正常 2=下架 3=删除
        if(!Objects.equals("1",item.getStatus())){
            throw new RuntimeException("通过传递的itemId查询的商品状态可能是下架或删除状态");
        }
        //2.获取该商品的商家ID(从item实体中获取)
        String sellerId = item.getSellerId();
        //3、调用封装方法，通过查询出来商品所属的商家的购物车是否在大购物车中已经存在，不存在返回null
        Cart cart = searchCartBySellerId(cartList, sellerId);
        //4.如果大购物车列表中不存在该商家的购物车
        if(cart==null){
            //4.1 新建该商家购物车对象(Cart对象)，能进来说明上面的cart对象就是Null，所以直接用上面的对象就好了。
            cart = new Cart();
            //4.2 往新的商家购物车对象中添加商家id、名称以及商品明细集合(orderItem对象集合)
            cart.setSellerId(sellerId);
            cart.setSellerName(item.getSeller());
            //创建一个商品明细集合，也就是商家购物车实体中的List<TbOrderItem>属性
            List<TbOrderItem> orderItemList = new ArrayList<>();
            //商家购物车中每一个商品，最终都会生成订单，所以可以用订单来表示每一条商品信息
            //调用封装方法，组装一个商品明细对象(商品明细集合中的商品明细对象)然后返回
            TbOrderItem orderItem = setOrderItem(item, num);
            //将返回的商品明细放入该商家购物车的商品明细集合
            orderItemList.add(orderItem);
            //商品明细集合存入商家购物车
            cart.setOrderItemList(orderItemList);
            //将当前新的商家购物车存入大购物车中
            cartList.add(cart);
        }else {//5.如果大购物车列表中存在该商家的购物车
            //如果存在该商家购物车，那么上面返回的cart商家购物车对象就不是null，从这个对象可以获取该商家购物车下的商品明细集合
            List<TbOrderItem> orderItemList = cart.getOrderItemList();
            //调用封装方法，通过这个商品明细集合中的每个商品的itemId和新增的itemId匹配。可以判断商家购物车中是否存在新增的商品
            //如果存在返回该商品明细对象，如果不存在该对象为Null
            TbOrderItem orderItem = searchOrderItemByItemId(orderItemList,itemId);
            //如果不存在
            if(orderItem == null){
                //调用封装方法，新增一个商品明细对象
                orderItem = setOrderItem(item,num);
                //你大购物车有该商家的购物车对象，但是这个商家购物车对象没有新增的这个商品，所以把这个商品放近商家购物车
                cart.getOrderItemList().add(orderItem);
            }else { //如果存在
                //如果大购物车存在该商家购物车，也存在了这个商品，那就给这个商品修改数量和总价
                orderItem.setNum(num + orderItem.getNum());
                orderItem.setTotalFee(new BigDecimal(orderItem.getPrice().doubleValue() * orderItem.getNum()));
                //如果该商品数量小于等于0
                if(orderItem.getNum() <= 0){
                    //就清除该商家购物车中该条商品
                    cart.getOrderItemList().remove(orderItem);
                }
                //如果清除完该商家购物车中商品明细后，该购物车中没有商品明细了
                if(cart.getOrderItemList().size() <= 0){
                    //就清除大购物车中该商家的购物车
                    cartList.remove(cart);
                }
            }
        }
        return cartList;
    }

    /**
     * 循环大购物车得出所有商家购物车实体，通过查询出来商品所属商家是否在大购物车中已经存在
     * @param cartList
     * @param sellerId
     */
    public Cart searchCartBySellerId(List<Cart> cartList,String sellerId){
        if(cartList == null || cartList.size() <= 0){
            return null;
        }
        //循环大购物车得出所有商家购物车实体
        for (Cart cart : cartList) {
            //通过查询出来商品所属商家id是否在大购物车中已经存在
            if(Objects.equals(cart.getSellerId(),sellerId)){
                //如果存在就把这个商家的购物车对象返回
                return cart;
            }
        }
        //不存在就返回Null
        return null;
    }

    /**
     * 组装一个orderItem对象(商品明细集合中的商品明细对象，也可理解为购物车页面中的一条商品对象)
     * @param item
     * @param num
     */
    private TbOrderItem setOrderItem(TbItem item, Integer num) {
        TbOrderItem orderItem = new TbOrderItem();
        orderItem.setGoodsId(item.getGoodsId());
        orderItem.setItemId(item.getId());
        orderItem.setNum(num);
        orderItem.setPicPath(item.getImage());
        orderItem.setSellerId(item.getSellerId());
        orderItem.setTitle(item.getTitle());
        orderItem.setPrice(item.getPrice());
        //计算总价  item.getPrice()获取的是BigDecimal类型，.doubleValue()转换成double然后和num相乘，结果再转换成BigDecimal
        orderItem.setTotalFee(new BigDecimal(item.getPrice().doubleValue() * num));
        return orderItem;
    }

    /**
     * 通过这个商品明细集合中的每个商品的itemId和新增的itemId匹配。可以判断商家购物车中是否存在新增的商品
     * @param orderItemList
     * @param itemId
     * @return
     */
    private TbOrderItem searchOrderItemByItemId(List<TbOrderItem> orderItemList, Long itemId) {
        //循环商品明细集合得出每一条商品明细对象
        for (TbOrderItem orderItem : orderItemList) {
            //通过这个商品明细集合中的每个商品的itemId和新增的itemId匹配。可以判断商家购物车中是否存在新增的商品
            if(orderItem.getItemId().longValue() == itemId.longValue()){
                //如果存在返回该存在的商品明细对象
                return orderItem;
            }
        }
        //不存在返回一个为Null的商品明细对象
        return null;
    }

    /**
     * 将购物车写入redis
     * @param cartList
     * @param username
     */
    @Override
    public void saveCartListToRedis(List<Cart> cartList, String username) {
        redisTemplate.boundHashOps("cartList").put(username,cartList);
        log.info("购物车数据成功写入redis");
    }

    /**
     * 根据用户选中的商品itemId去该用户的购物车中获取并组装成购物车集合返回
     * @param itemIds
     * @param username
     * @return
     */
    @Override
    public List<Cart> getItemsByItemId(List<Long> itemIds, String username) {
        //取出该用户的购物车（全部的）
        List<Cart> cartList = (List<Cart>)redisTemplate.boundHashOps("cartList").get(username);
        //创建一个新的购物车用于存储该用户选中的商品
        List<Cart> carts = new ArrayList<>();
        //循环获取该用户选中的商品数据
        for (Cart cart1 : cartList) {

            Cart cart =  new Cart();
            List<TbOrderItem> orderItems = new ArrayList<>();

            List<TbOrderItem> orderItemList = cart1.getOrderItemList();
            for (TbOrderItem orderItem : orderItemList) {
                for (Long itemId : itemIds) {
                    if(orderItem.getItemId().equals(itemId)){
                        orderItems.add(orderItem);
                    }
                }
            }
            if(orderItems.size() > 0){
                cart.setOrderItemList(orderItems);
                cart.setSellerName(cart1.getSellerName());
                cart.setSellerId(cart1.getSellerId());
                carts.add(cart);
            }
        }
        return carts;
    }


    /**
     * 删除购物车中的商品明细，并返回删除过后的购物车集合
     * @param cartsList
     * @param itemId
     * @return
     */
    @Override
    public List<Cart> deleteCartOrderItem(List<Cart> cartsList, Long itemId) {
        //遍历大购物车获取每一个商家购物车
        TbOrderItem orderItem = new TbOrderItem();

        for (Cart cart : cartsList) {
            List<TbOrderItem> orderItemList = cart.getOrderItemList();
            for (TbOrderItem tbOrderItem : orderItemList) {
                if(tbOrderItem.getItemId().equals(itemId)){
                    orderItem = tbOrderItem;
                }
            }
            orderItemList.remove(orderItem);
        }
        //把删除过后的购物车返回
        return cartsList;
    }
}
